home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- Module name: hash strings to integers.
-
- Author: S. Larkin.
-
- Function: Contains routines to manipulate a table of hashtables.
- The routines allocate unique integer id`s to strings
- and also allow retrieval of these strings via their unique id`s.
-
- Dependencies: machine.h.
-
- External function list:
- ptk_inithashtables
- ptk_idtostring
- ptk_delstring
- ptk_delhashtable
- ptk_stringtoid
- ptk_stringused
- ptk_inqstrings
- ptk_inqhashtables
- ptk_storehashtable
- ptk_storeallhashtables
- ptk_restorehashtable
- ptk_restoreallhashtables
- ptk_createhashtable
- ptk_hashtableused
-
- Internal function list:
- searchforstring
- getnextstrid
- freestrid
- hashstring
- parsestring
- stringlength
- outputfreeidlist
- addstring
- addstringtotable
- addtabletotable
- ptk_stringtotable
-
- Hashtables used: all.
-
- Modification history : (Version), (Date), (Name), (Description).
-
- 1.0, 18th August 1988, S. Larkin, First version.
-
- 1.1, 7th November 1988, S. Larkin, This module now
- supports a fixed number ( 10 ) of independent hashtables.
- All functions now take a table parameter which specifies
- which hashing table is being accessed.
- Two new func/proc have been added:
- string_Used which returns TRUE if the supplied
- string has been used in the hashing table.
- Inquire_table which returns details about appropriate
- hashtable.
-
- 2.0, 4th January 1991, G. Williams, Converted from Pascal
- to C. Function names changed to PHIGS Toolkit convention - ptk_xxx.
- There is now no restriction on the number of hashtables, the user
- must call ptk_hashinitialise to initialise a hashtable. Each hashtable
- has a specified range of structure identifiers which is supplied by
- the user.
-
- 2.1, 18th March 1991, G. Williams, new strategy - a table of tables.
-
- 3.0, June 1992, G. Williams, Converted to ISO PHIGS C.
-
- ----------------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef SUN
- #include <malloc.h>
- #endif
- #ifdef PEXSI
- #include <malloc.h>
- #endif
- #include <phigs.h>
- #include "machine.h"
- #include "ptktype.h"
- #include "hashtype.h"
- #include "perrfns.h"
-
- #define NIL -1
-
- #define sizeofhashtable 1009
-
- typedef struct ptksstridentry
- {
- char *strdata;
- Pint stringlen;
- Pint uniqint;
- Pint clashptr, prevptr;
- } ptksstridentry;
-
- typedef Pint ptkahashtablecont[sizeofhashtable];
-
- typedef struct ptksfreeint
- {
- Pint freeint;
- struct ptksfreeint *next;
- } ptksfreeint;
-
- typedef struct ptkshashtable
- {
- ptkahashtablecont hashtable;
- Pint numstrings;
- Pint minuniqint;
- Pint maxuniqint;
- ptksstridentry *stridtable;
- ptksfreeint *freeintlist;
- } ptkshashtable;
-
- typedef struct ptkstableentry
- {
- char *strdata;
- Pint stringlen;
- ptkshashtable *tableptr;
- Pint clashptr, prevptr;
- } ptkstableentry;
-
- typedef struct ptkshashtablelst
- {
- ptkahashtablecont hashtable;
- Pint numtables;
- ptkstableentry *tablelist;
- ptksfreeint *freeintlist;
- } ptkshashtablelst;
-
- static ptkshashtablelst toptable;
- static ptkboolean PTKINITHASH = FALSE;
-
- /*--------------------------------------------------------------------------*/
-
- static Pint hashstring(C(char *)str, C(Pint) strlength)
- PreANSI(char *str)
- PreANSI(Pint strlength)
- /*
- ** \blurb{This function returns a hash value in the range 1 to `sizeofhashtable'.}
- ** \param{str}{string}
- ** \param{strlength}{length of string. }
- ** none.
- ** return value: hash value of str.
- */
- {
- Pint i, l, shift;
- unsigned int res, ch;
-
- l = 0;
- res = 0;
- shift = 1;
- for (i = 0; i < strlength; i++)
- {
- ch = (unsigned int)str[i] * shift;
- res ^= ch;
- l++;
- if (shift == 1)
- shift = 256;
- else
- shift *= 256;
- if (l == 4)
- {
- l = 0;
- shift = 1;
- }
- }
- return (res % sizeofhashtable + 1);
- } /* hashstring */
-
- /*--------------------------------------------------------------------------*/
-
- static void searchforstring(C(char *)sname, C(Pint) startentry,
- C(ptkshashtable *)table,
- C(Pint *)foundentry, C(ptkboolean *)isfound)
- PreANSI(char *sname)
- PreANSI(Pint startentry)
- PreANSI(ptkshashtable *table)
- PreANSI(Pint *foundentry)
- PreANSI(ptkboolean *isfound)
- /*
- ** \blurb{Searches for the given string in a hashtable.}
- ** \param{sname}{string to search for}
- ** \param{startentry}{position to start searching for string in string table}
- ** \param{table}{hashtable}
- ** \param{foundentry}{position in string table of string}
- ** \param{isfound}{TRUE if string is in table, FALSE if not}
- ** return value: none.
- */
- {
- Pint nextentry;
- ptksstridentry *entry;
-
- *isfound = FALSE;
- if (startentry != NIL)
- {
- do
- {
- entry = &table->stridtable[startentry];
- if (entry->strdata != NULL)
- if (!strncmp(entry->strdata, sname, strlen(entry->strdata)))
- *isfound = TRUE;
- if (!*isfound)
- {
- /* check next id */
- nextentry = entry->prevptr;
- if (nextentry != NIL)
- startentry = nextentry;
- }
- } while (*isfound != TRUE && nextentry != NIL);
- }
- *foundentry = startentry;
- } /* searchforstring */
-
- /*--------------------------------------------------------------------------*/
-
- static void searchfortable(C(char *)tabname, C(Pint) startentry,
- C(Pint *)foundentry, C(ptkboolean *)isfound)
- PreANSI(char *tabname)
- PreANSI(Pint startentry)
- PreANSI(Pint *foundentry)
- PreANSI(ptkboolean *isfound)
- /*
- ** \blurb{Searches for the given table name in hashtable table.}
- ** \param{tabname}{name of table to search for}
- ** \param{startentry}{position to start searching for table in hashtable table}
- ** \param{table}{hashtable table}
- ** \param{foundentry}{position in hashtable table of table}
- ** \param{isfound}{TRUE if table is in hashtable table, FALSE if not}
- **
- ** return value: none.
- */
- {
- Pint nextentry;
- ptkstableentry *entry;
-
- *isfound = FALSE;
- if (startentry != NIL)
- {
- do
- {
- entry = &toptable.tablelist[startentry];
- if (entry->strdata != NULL)
- if (!strncmp(entry->strdata, tabname, strlen(entry->strdata)))
- *isfound = TRUE;
- if (!*isfound)
- {
- /* check next id */
- nextentry = entry->prevptr;
- if (nextentry != NIL)
- startentry = nextentry;
- }
- } while (*isfound != TRUE && nextentry != NIL);
- }
- *foundentry = startentry;
- } /* searchfortable */
-
- /*--------------------------------------------------------------------------*/
-
- static Pint getnextstrid(C(ptksfreeint **) freelist)
- PreANSI(ptksfreeint **freelist)
- /*
- ** \blurb{Returns next free string id, returns 0 if no more left.}
- ** \param{table}{hashtable}
- ** return value: next free string identifier.
- ** error conditions: table->freeintlist == NULL - no more free string id's.
- */
- {
- Pint result;
-
- result = 0;
- if (*freelist == NULL)
- {
- fprintf(stderr, "HashStrings: Run out of integers to allocate\n");
- return result;
- }
- result = (*freelist)->freeint;
- if ((*freelist)->next == NULL) /* end of list */
- ((*freelist)->freeint)++; /* make next id free */
- else
- *freelist = (*freelist)->next;
- return result;
- } /* getnextstrid */
-
- /*--------------------------------------------------------------------------*/
-
- static void freestrid(C(ptksfreeint **) freelist, C(Pint) fid)
- PreANSI(ptksfreeint **freelist)
- PreANSI(Pint fid)
- /*
- ** \blurb{Fid is placed on the freeintlist so it can be used again. }
- ** \param{table}{hashtable}
- ** \param{fid}{string identifier to be made free}
- ** special notes: this function is used when a string has been deleted from
- ** the string table and it's corresponding string identifier is made
- ** available for a new string.
- */
- {
- ptksfreeint *temp;
-
- temp = (ptksfreeint *)malloc(sizeof(ptksfreeint));
- temp->freeint = fid;
- temp->next = *freelist;
- *freelist = temp;
- } /* freestrid */
-
- /*--------------------------------------------------------------------------*/
-
- static Pint stringlength(C(char *)str)
- PreANSI(char *str)
- /*
- ** \blurb{Returns length of string up to first ' '(space), '\n' or '\0'
- ** character.}
- ** \param{str}{string to find length of}
- ** return value: length of string.
- ** special notes: The hashstrings algorithm does not permit strings with
- ** spaces, hence the search for the first space character. The C library
- ** routine `strlen' assumes there is a `\0' character terminating the string,
- ** however it is safer to look for a `\n' character aswell.
- */
- {
- ptkboolean charfound;
- Pint ind;
-
- ind = 0;
- charfound = FALSE;
- while (!charfound)
- {
- if (str[ind] == '\n' || str[ind] == '\0')
- charfound = TRUE;
- else
- ind++;
- }
- return ind;
- } /* stringlength */
-
- /*--------------------------------------------------------------------------*/
-
- static void parsestring(C(char *)beforestr, C(char *)afterstr,
- C(Pint) strlength)
- PreANSI(char *beforestr)
- PreANSI(char *afterstr)
- PreANSI(Pint strlength)
- /*
- ** \blurb{All upper case characters are converted to lowercase
- ** and a `\0' character is put on end of the string.}
- ** \param{beforestr}{string to be parsed}
- ** \param{strlength}{length of parsed string}
- ** \param{afterstr}{parsed string}
- */
- {
- Pint ind;
-
- for (ind = 0; ind < strlength; ind++)
- {
- if (isupper(beforestr[ind]))
- afterstr[ind] = beforestr[ind] - ('A' - 'a');
- else
- afterstr[ind] = beforestr[ind];
- }
- afterstr[ind] = '\0';
- } /* parsestring */
-
- /*--------------------------------------------------------------------------*/
-
- static ptkboolean addstringtotable(C(ptkshashtable *) table, C(char *) str,
- C(Pint *) strint)
- PreANSI(ptkshashtable *table)
- PreANSI(char *str)
- PreANSI(Pint *strint)
- /*
- ** \blurb{Adds a string entry to the string table of a given
- ** hashtable. Reallocates the whole string table if necessary.}
- ** \param{table}{hashtable to add string to}
- ** \param{str}{string to add to table}
- */
- {
- ptksstridentry *strentry;
- Pint strlength;
- ptkboolean needrealloc;
-
- /* allocate space for string entry */
- /* if strint < number of strings in list then no need to reallocate */
-
- if (table->freeintlist->next == NULL)
- needrealloc = TRUE;
- else
- needrealloc = FALSE;
-
- *strint = getnextstrid(&table->freeintlist);
- if (*strint > table->maxuniqint)
- {
- fprintf(stderr, "HashStrings: Run out of integers to allocate\n");
- return FALSE;
- }
-
- if (needrealloc)
- {
- table->numstrings++;
- table->stridtable = (ptksstridentry *)realloc(table->stridtable,
- table->numstrings * sizeof(ptksstridentry));
- }
-
- strlength = strlen(str);
- strentry = (table->stridtable + (*strint - table->minuniqint));
- strentry->strdata = (char *)malloc(strlength + 1);
- strncpy(strentry->strdata, str, (strlength + 1));
- strentry->stringlen = strlength;
- strentry->uniqint = *strint;
- strentry->clashptr = NIL;
- strentry->prevptr = NIL;
- return TRUE;
- } /* addstringtotable */
-
- /*--------------------------------------------------------------------------*/
-
- static Pint addtabletotable(C(char *) str)
- PreANSI(char *str)
- /*
- ** \blurb{Adds a hashtable to the table of hashtables.
- ** Reallocates the whole table of hashtable names if necessary.}
- ** \param{table}{table of hashtables}
- ** \param{str}{name of new hashtable}
- */
- {
- ptkstableentry *tabentry;
- Pint stid, strlength;
-
- /* allocate space for string entry */
- /* if stid < number of tables in list then no need to reallocate */
-
- if (toptable.freeintlist->next == NULL)
- {
- toptable.numtables++;
- toptable.tablelist = (ptkstableentry *)realloc(toptable.tablelist,
- toptable.numtables * sizeof(ptkstableentry));
- }
- stid = getnextstrid(&toptable.freeintlist);
- strlength = strlen(str);
- tabentry = &toptable.tablelist[stid];
- tabentry->strdata = (char *)malloc(strlength + 1);
- strncpy(tabentry->strdata, str, (strlength + 1));
- tabentry->stringlen = strlength;
- tabentry->clashptr = NIL;
- tabentry->prevptr = NIL;
- return stid;
- } /* addtabletotable */
-
- /*--------------------------------------------------------------------------*/
-
- static void ptk_hashinitialise(C(ptkshashtable *)table, C(Pint) minint,
- C(Pint) maxint)
- PreANSI(ptkshashtable *table)
- PreANSI(Pint minint)
- PreANSI(Pint maxint)
- /*
- ** \blurb{Initialises table structure, containing hashtable, minuniqint,
- ** maxuniqint, freeintlist and stridtable.
- ** Function checks values of minint and maxint in case
- ** user gets them the wrong way round.}
- ** \param{table}{hashtable}
- ** \param{minint}{lower limit of string identifier range}
- ** \param{maxint}{upper limit of string identifier range}
- */
- {
- Pint ind;
-
- for (ind = 0; ind < sizeofhashtable; ind++)
- table->hashtable[ind] = NIL;
- table->stridtable = (ptksstridentry *)malloc(sizeof(ptksstridentry));
- table->numstrings = 0;
- if (minint < maxint)
- {
- table->minuniqint = minint; /* minimum structure identifier */
- table->maxuniqint = maxint; /* maximum structure identifier */
- }
- else
- {
- table->minuniqint = maxint;
- table->maxuniqint = minint ;
- }
- table->freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint));
- table->freeintlist->freeint = table->minuniqint; /* first free id */
- table->freeintlist->next = NULL;
- } /* ptk_hashinitialise */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_inithashtables(C(void))
- /* PreANSI() */
- /*
- ** \blurb{This function initialises the table in which the details of
- ** hashtables created by the application are kept. This function
- ** must be called before any other hashtable functions.}
- */
- {
- Pint ind;
-
- for (ind = 0; ind < sizeofhashtable; ind++)
- toptable.hashtable[ind] = NIL;
- toptable.tablelist = (ptkstableentry *)malloc(sizeof(ptkstableentry));
- toptable.numtables = 0;
- toptable.freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint));
- toptable.freeintlist->freeint = 0; /* first free id */
- toptable.freeintlist->next = NULL;
- PTKINITHASH = TRUE;
- } /* ptk_inithashtables */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern ptkboolean ptk_hashtableused(C(char *)str)
- PreANSI(char *str)
- /*
- ** \parambegin
- ** \param{char *}{str}{name of hashtable}{IN}
- ** \paramend
- ** \blurb{This function checks if a hashtable named \pardesc{str}
- ** already exists in the table of
- ** hashtables, returning TRUE if the hashtable exists, otherwise FALSE.}
- */
- {
- Pint hashvalue, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
-
- if (!PTKINITHASH)
- return FALSE;
- strlength = stringlength(str);
- newstr = (char *)malloc(strlength + 1);
- parsestring(str, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (toptable.hashtable[hashvalue - 1] == NIL)
- {
- /* not present */
- return FALSE;
- }
- else
- {
- /* collision, so traverse clash pointers to search for occurence */
- searchfortable(newstr, toptable.hashtable[hashvalue - 1],
- &foundentry, &found);
- return found;
- }
- } /* ptk_hashtableused */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_createhashtable(C(char *) tablestr, C(Pint) minint,
- C(Pint) maxint)
- PreANSI(char *tablestr)
- PreANSI(Pint minint)
- PreANSI(Pint maxint)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{hashtable name}{IN}
- ** \param{Pint}{minint}{lower limit of string-integer range}{IN}
- ** \param{Pint}{maxint}{upper limit of string-integer range}{IN}
- ** \paramend
- ** \blurb{This function creates a new hashtable, with the name \pardesc{tablestr}.
- ** \pardesc{minint} and \pardesc{maxint} respectively specify the lower and
- ** upper limits of the range of
- ** integers to which strings hashed into the hashtable will be mapped.}
- */
- {
- Pint hashvalue, stid, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
-
- if (!PTKINITHASH)
- {
- fprintf(stderr, "HashStrings: Hashtables have not been initialised\n");
- return;
- }
- /* check if string exists in top table */
- if (!ptk_hashtableused(tablestr))
- {
- /* addstringtotable */
-
- strlength = stringlength(tablestr);
- newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
- parsestring(tablestr, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (toptable.hashtable[hashvalue - 1] == NIL)
- {
- /* no collision, so add string */
- stid = addtabletotable(newstr);
- toptable.hashtable[hashvalue - 1] = stid;
- free(newstr);
- }
- else
- {
- /* collision, so traverse clash pointers to first free position */
- searchfortable(newstr, toptable.hashtable[hashvalue - 1],
- &foundentry, &found);
-
- /* add into table */
- stid = addtabletotable(newstr);
- toptable.hashtable[hashvalue - 1] = stid;
- toptable.tablelist[foundentry].clashptr = stid;
- toptable.tablelist[stid].prevptr = foundentry;
- free(newstr);
- } /* else */
-
- toptable.tablelist[stid].tableptr =
- (ptkshashtable *)malloc(sizeof(ptkshashtable));
- ptk_hashinitialise(toptable.tablelist[stid].tableptr, minint, maxint);
- }
- } /* ptk_createhashtable */
-
- /*--------------------------------------------------------------------------*/
-
- static ptkshashtable * ptk_stringtotable(C(char *)str)
- PreANSI(char *str)
- /*
- ** \parambegin
- ** \param{char *}{str}{name of hashtable}{IN}
- ** \paramend
- ** \blurb{Returns pointer to a hashtable.}
- */
- {
- Pint hashvalue, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
-
- strlength = stringlength(str);
- newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
- parsestring(str, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (toptable.hashtable[hashvalue - 1] == NIL)
- {
- /* no collision, so no table */
- free(newstr);
- fprintf(stderr, "HashStrings: Hashtable \"%s\" doesn't exist\n", str);
- return NULL;
- }
- else
- {
- /* collision, so traverse clash pointers to first free position */
- searchfortable(newstr, toptable.hashtable[hashvalue - 1],
- &foundentry, &found);
- free(newstr);
- return toptable.tablelist[foundentry].tableptr;
- } /* else */
- } /* ptk_stringtotable */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_inttostring(C(char *) tablestr, C(Pint) stint,
- C(Pint) size, C(char *) strbuffer,
- C(Pint *) buffersize)
- PreANSI(char *tablestr)
- PreANSI(Pint stint)
- PreANSI(Pint size)
- PreANSI(char *strbuffer)
- PreANSI(Pint *buffersize)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{hashtable name}{IN}
- ** \param{Pint}{stint}{string identifier to search hashtable for}{IN}
- ** \param{Pint}{size}{number of bytes allocated by the user for the string}{IN}
- ** \param{char *}{strbuffer}{pointer to space allocated by the user for the string}{OUT}
- ** \param{Pint *}{buffersize}{actual size of buffer required}{OUT}
- ** \paramend
- ** \blurb{This function returns the string in hashtable \pardesc{tablestr}
- ** which has been allocated the integer
- ** \pardesc{stint}. The string is returned in the buffer \pardesc{strbuffer},
- ** which must be allocated by the application. The number of bytes actually used
- ** in the buffer is returned in \pardesc{buffersize}, as
- ** the length of string + 1 (for `\\0' character),
- ** or 0 if no string was returned.}
- */
- {
- ptksstridentry *strentry;
- ptkshashtable *table;
- Pint i;
- ptkboolean found;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- found = FALSE;
- i = 0;
- while ((i < table->numstrings) && (!found))
- {
- strentry = &table->stridtable[i];
- if ((strentry->uniqint == stint) && (strentry->strdata != NULL))
- found = TRUE;
- else
- i++;
- }
-
- if (!found)
- {
- /* no string allocated */
- *buffersize = 0;
- return;
- }
- else
- {
- *buffersize = (strentry->stringlen + 1);
-
- /* check buffer size */
- if (size >= *buffersize)
- {
- /* copy string into buffer.
- ** NB: this routine relies on the user being truthful about the
- ** size of the buffer, if not errors may occur.
- */
- strncpy(strbuffer, strentry->strdata, *buffersize);
- }
- }
- }
- } /* ptk_inttostring */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern Pint ptk_stringtoint(C(char *) tablestr, C(char *) str)
- PreANSI(char *tablestr)
- PreANSI(char *str)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{name of hashtable}{IN}
- ** \param{char *}{str}{string to be searched for in string table}{IN}
- ** \paramend
- ** \blurb{This function returns the integer allocated for the string \pardesc{str}
- ** in hashtable \pardesc{tablestr}.
- ** If the string has not already been allocated an integer,
- ** then it is allocated one and this value is
- ** returned.}
- */
- {
- Pint hashvalue, stid, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
- ptkshashtable *table;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- strlength = stringlength(str);
- newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
- parsestring(str, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (table->hashtable[hashvalue - 1] == NIL)
- {
- /* no collision, so add string */
- if (addstringtotable(table, newstr, &stid))
- table->hashtable[hashvalue - 1] = stid - table->minuniqint;
- free(newstr);
- return stid;
- }
- else
- {
- /* collision, so traverse clash pointers to first free position */
- searchforstring(newstr, table->hashtable[hashvalue - 1],
- table, &foundentry, &found);
- if (found)
- {
- free(newstr);
- return table->stridtable[foundentry].uniqint;
- /* string already present */
- }
- else
- {
- /* add into table */
- if (addstringtotable(table, newstr, &stid))
- {
- table->hashtable[hashvalue - 1] = stid - table->minuniqint;
- table->stridtable[stid - table->minuniqint].prevptr = foundentry;
- table->stridtable[foundentry].clashptr = stid - table->minuniqint;
- }
- free(newstr);
- return stid;
- } /* else */
- } /* else */
- }
- } /* ptk_stringtoint */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern ptkboolean ptk_delstring(C(char *) tablestr, C(char *) delstr)
- PreANSI(char *tablestr)
- PreANSI(char *delstr)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{name of hashtable}{IN}
- ** \param{char *}{delstr}{string to be deleted from string table}{IN}
- ** \paramend
- ** \blurb{This function deletes the string \pardesc{delstr} from hashtable
- ** \pardesc{tablestr}. The result of the function is
- ** TRUE if the string was, otherwise FALSE.}
- */
- {
- Pint hashvalue, strlength;
- char *newstr;
- ptkboolean found;
- ptksstridentry *strentry;
- Pint foundentry;
- ptkshashtable *table;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- strlength = stringlength(delstr);
- newstr = (char *)malloc(strlength + 1);
- parsestring(delstr, newstr, strlength);
- hashvalue = hashstring(newstr, strlength);
- searchforstring(newstr, table->hashtable[hashvalue - 1], table,
- &foundentry, &found);
- if (!found)
- {
- free(newstr);
- /* string not present */
- return FALSE;
- }
- else
- {
- free(newstr);
- strentry = &table->stridtable[foundentry];
- if (strentry->prevptr == NIL)
- {
- /* entry at head of list */
- if (strentry->clashptr == NIL) /* only one entry */
- table->hashtable[hashvalue - 1] = NIL;
- else
- {
- /* more than one entry in list */
- table->stridtable[(strentry->clashptr)].prevptr = NIL;
-
- /* by-pass deleted entry
- table->hashtable[hashvalue - 1] = strentry->clashptr; */
- }
- } /* if */
- else
- if (strentry->clashptr == NIL) /* at end of list */
- {
- table->hashtable[hashvalue - 1] = strentry->prevptr;
- table->stridtable[(strentry->prevptr)].clashptr = NIL;
- }
- else
- {
- /* in middle of list, so by-pass entry */
- table->stridtable[(strentry->prevptr)].clashptr =
- strentry->clashptr;
- table->stridtable[(strentry->clashptr)].prevptr =
- strentry->prevptr;
- }
- free(table->stridtable[foundentry].strdata); /* retrieve id */
- table->stridtable[foundentry].strdata = NULL;
- table->stridtable[foundentry].clashptr = NIL;
- table->stridtable[foundentry].prevptr = NIL;
- freestrid(&table->freeintlist, table->stridtable[foundentry].uniqint);
- return TRUE;
- }
- }
- } /* ptk_delstring */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern ptkboolean ptk_delhashtable(C(char *) tablestr)
- PreANSI(char *tablestr)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{name of table to be deleted}{IN}
- ** \paramend
- ** \blurb{This function deletes hastable \pardesc{tablestr} from the
- ** table of hashtables,
- ** returning TRUE if the table was deleted, otherwise FALSE.}
- */
- {
- Pint hashvalue, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
- ptkshashtable *delptr;
- ptkstableentry *tabentry;
- ptksfreeint *freeptr, *nextptr;
- Pint i;
-
- strlength = stringlength(tablestr);
- newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
- parsestring(tablestr, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (toptable.hashtable[hashvalue - 1] == NIL)
- {
- /* no collision, so no table */
- free(newstr);
- return FALSE;
- }
- else
- {
- /* collision, so traverse clash pointers to first free position */
- searchfortable(newstr, toptable.hashtable[hashvalue - 1],
- &foundentry, &found);
-
- /* get pointer to hashtable */
-
- delptr = toptable.tablelist[foundentry].tableptr;
-
- /* delete each string in hashtable */
-
- /* free string table */
-
- for (i = 0; i < delptr->numstrings; i++)
- {
- free(delptr->stridtable[i].strdata);
- free(delptr->stridtable[i]);
- }
-
- /* free freeintlist */
- freeptr = delptr->freeintlist;
- if (freeptr != NULL)
- {
- nextptr = freeptr->next;
- free(freeptr);
- freeptr = nextptr;
- }
-
- /* free ptkshashtable */
-
- free(delptr);
-
- toptable.tablelist[foundentry].tableptr = NULL;
-
- /* delete tableentry from ptkshashtablelst */
-
- tabentry = &toptable.tablelist[foundentry];
- if (tabentry->prevptr == NIL)
- {
- /* entry at head of list */
- if (tabentry->clashptr == NIL) /* only one entry */
- toptable.hashtable[hashvalue - 1] = NIL;
- else
- {
- /* more than one entry in list */
- toptable.tablelist[(tabentry->clashptr)].prevptr = NIL;
-
- /* by-pass deleted entry
- toptable.hashtable[hashvalue - 1] = tabentry->clashptr; */
- }
- } /* if */
- else
- if (tabentry->clashptr == NIL) /* at end of list */
- {
- toptable.tablelist[(tabentry->prevptr)].clashptr = NIL;
- toptable.hashtable[hashvalue - 1] = tabentry->prevptr;
- }
- else
- {
- /* in middle of list, so by-pass entry */
- toptable.tablelist[(tabentry->prevptr)].clashptr =
- tabentry->clashptr;
- toptable.tablelist[(tabentry->clashptr)].prevptr =
- tabentry->prevptr;
- }
- free(toptable.tablelist[foundentry].strdata); /* retrieve id */
- toptable.tablelist[foundentry].strdata = NULL;
- toptable.tablelist[foundentry].clashptr = NIL;
- toptable.tablelist[foundentry].prevptr = NIL;
- free(newstr);
- return TRUE;
- } /* else */
- } /* ptk_delhashtable */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern ptkboolean ptk_stringused(C(char *) tablestr, C(char *) str)
- PreANSI(char *tablestr)
- PreANSI(char *str)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{name of hashtable}{IN}
- ** \param{char *}{str}{string to search for in string table}{IN}
- ** \paramend
- ** \blurb{This function checks if the string \pardesc{str}
- ** has already been used in hashtable \pardesc{tablestr},
- ** Returning TRUE if string was used in the hashtable, otherwise FALSE.}
- */
- {
- Pint hashvalue, strlength;
- char *newstr;
- ptkboolean found;
- Pint foundentry;
- ptkshashtable *table;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- strlength = stringlength(str);
- newstr = (char *)malloc(strlength + 1);
- parsestring(str, newstr, strlength);
- hashvalue = hashstring(newstr, strlength); /* calc hashvalue */
- if (table->hashtable[hashvalue - 1] == NIL)
- {
- /* not present */
- return FALSE;
- }
- else
- {
- /* collision, so traverse clash pointers to search for occurence */
- searchforstring(newstr, table->hashtable[hashvalue - 1], table,
- &foundentry, &found);
- return found;
- }
- }
- } /* ptk_stringused */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_inqstrings(C(char *) tablestr, C(Pint) size,
- C(Pint *) totalsize, C(char *) strbuffer,
- C(ptksstringtable *) strtable)
-
- PreANSI(char *tablestr)
- PreANSI(Pint size)
- PreANSI(Pint *totalsize)
- PreANSI(char *strbuffer)
- PreANSI(ptksstringtable *strtable)
- /*
- ** \parambegin
- ** \param{char *}{tablestr}{name of hashtable}{IN}
- ** \param{Pint}{size}{number of bytes allocated by the user for string table data.}{IN}
- ** \param{Pint *}{totalsize}{actual size of buffer required for string table data.}{OUT}
- ** \param{char *}{strbuffer}{application supplied buffer for string table data}{OUT}
- ** \param{ptksstringtable *}{strtable}{struct containing length of arrays and pointer to data in strbuffer.}{OUT}
- ** \paramend
- ** \blurb{This function is used to interogate hashtable \pardesc{tablestr}.
- ** A list of the \pardesc{size} strings contained in the hashtable are returned
- ** in the user specified buffer \pardesc{strbuffer}, together with their
- ** corresponding
- ** string lengths and integer hash values.}
- */
- {
- Pint ind;
- ptksstridentry *strentry;
- Pint *stidptr;
- Pint *strlenptr;
- char **strptr;
- char *stringptr;
- Pint counter = 0;
- ptkshashtable *table;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- *totalsize = 0;
- for (ind = 0; ind < table->numstrings; ind++)
- {
- strentry = (table->stridtable + ind);
- if (strentry->strdata != NULL)
- {
- *totalsize += (2 * sizeof(Pint)) + sizeof(char *) +
- (strentry->stringlen + 1);
- counter++;
- }
- }
-
- strtable->listlen = counter;
- /* if application buffer is big enough, copy in data */
- if (counter > 0)
- {
- if ((size >= *totalsize) && (strbuffer != NULL))
- {
- /* pointers into application supplied buffer */
- stidptr = strtable->intlist = (Pint *)strbuffer;
- strlenptr = strtable->strlenlist = (Pint *)(strbuffer +
- (counter * sizeof(Pint)));
- strptr = strtable->strlist = (char **)(strbuffer +
- (2 * (counter * sizeof(Pint))));
- stringptr = (char *)(strptr + (counter * sizeof(char *)));
- for (ind = 0; ind < table->numstrings; ind++)
- {
- if ((table->stridtable + ind)->strdata != NULL)
- {
- strentry = (table->stridtable + ind);
- strncpy(stringptr, strentry->strdata,
- (strentry->stringlen + 1));
- *strptr = (char *)stringptr;
- strptr++;
- stringptr += (strentry->stringlen + 2);
- *strlenptr = (Pint)strentry->stringlen;
- strlenptr++;
- *stidptr = (Pint)strentry->uniqint;
- stidptr++;
- }
- }
- }
- }
- }
- } /* ptk_inqstrings */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_inqhashtables(C(Pint) size, C(Pint *) totalsize,
- C(char *) strbuffer, C(ptkstablelist *) tablerec)
- PreANSI(Pint size)
- PreANSI(Pint *totalsize)
- PreANSI(char *strbuffer)
- PreANSI(ptkstablelist *tablerec)
- /*
- ** \parambegin
- ** \param{Pint}{size}{number of bytes allocated for the hashtable data.}{IN}
- ** \param{Pint *}{totalsize}{actual number of bytes required for hashtable data.}{OUT}
- ** \param{char *}{strbuffer}{pointer to buffer for hashtable data}{OUT}
- ** \param{ptkstablelist *}{tablerec}{hash table data.}{OUT}
- ** \paramend
- ** \blurb{This function returns in the
- ** user specified buffer \pardesc{strbuffer}
- ** the names of each hashtable contained in the table of hashtables.}
- */
- {
- Pint ind;
- ptkstableentry *tabentry;
- Pint *strlenptr;
- char **strptr;
- char *stringptr;
- Pint counter = 0;
-
- *totalsize = 0;
- for (ind = 0; ind < toptable.numtables; ind++)
- {
- tabentry = &toptable.tablelist[ind];
- if ((tabentry->tableptr) != NULL)
- {
- *totalsize += sizeof(Pint) + sizeof(char *) +
- (tabentry->stringlen + 1);
- counter++;
- }
- }
-
- tablerec->listlen = counter;
- /* if application buffer is big enough, copy in data */
- if (counter > 0)
- {
- if ((size >= *totalsize) && (strbuffer != NULL))
- {
- /* pointers into application supplied buffer */
- strlenptr = tablerec->namelenlist = (Pint *)(strbuffer);
- strptr = tablerec->tablenames = (char **)(strbuffer +
- (counter * sizeof(Pint)));
- stringptr = (char *)(strptr + (counter * sizeof(char *)));
- for (ind = 0; ind < toptable.numtables; ind++)
- {
- tabentry = &toptable.tablelist[ind];
- if (tabentry->tableptr != NULL)
- {
- strncpy(stringptr, tabentry->strdata,
- (tabentry->stringlen + 1));
- *strptr = (char *)stringptr;
- strptr++;
- stringptr += (tabentry->stringlen + 2);
- *strlenptr = (Pint)tabentry->stringlen;
- strlenptr++;
- }
- }
- }
- }
- } /* ptk_inqhashtables */
-
- /*--------------------------------------------------------------------------*/
-
- static void outputfreeintlist(C(FILE *) f, C(ptksfreeint *) freeptr)
- PreANSI(FILE *f)
- PreANSI(ptksfreeint *freeptr)
- /*
- ** \parambegin
- ** \param{ }{f}{pointer to a file}{IN}
- ** \param{ }{freeptr}{free identifier list}{IN}
- ** \paramend
- ** \blurb{Outputs the free identifier list to a file in
- ** reverse order.}
- */
- {
- if (freeptr != NULL)
- {
- outputfreeintlist(f, freeptr->next);
- fprintf(f, "%d\n", freeptr->freeint);
- }
- } /* outputfreeintlist */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_storehashtable(C(FILE *) fileptr, C(char *) tablestr)
- PreANSI(FILE *fileptr)
- PreANSI(char *tablestr)
- /*
- ** \parambegin
- ** \param{FILE *}{fileptr}{pointer to a file}{IN}
- ** \param{char *}{table}{hashtable to store}{IN}
- ** \paramend
- ** \blurb{The function writes the hashtable \pardesc{tablestr} to the
- ** file \pardesc{fileptr}, which should be opened and writeable.}
- */
- {
- Pint ind;
- Pint numstrs;
- ptksfreeint *freeptr;
- ptksstridentry *strentry;
- ptkshashtable *table;
-
- if ((table = ptk_stringtotable(tablestr)) != NULL)
- {
- fprintf(fileptr, "start\n");
- /* output structure identifier range */
- fprintf(fileptr, "%d\n", table->minuniqint);
- fprintf(fileptr, "%d\n", table->maxuniqint);
- numstrs = 0;
- for (ind = 0; ind < table->numstrings; ind++)
- {
- if ((table->stridtable + ind)->strdata != NULL)
- numstrs++;
- }
- fprintf(fileptr, "%d\n", numstrs);
- /* output string table entries */
- for (ind = 0; ind < table->numstrings; ind++)
- {
- if ((table->stridtable + ind)->strdata != NULL)
- {
- strentry = (table->stridtable + ind);
- fprintf(fileptr, "%d\n", (strentry->stringlen + 1));
- fprintf(fileptr, "%s\n", strentry->strdata);
- fprintf(fileptr, "%d\n", strentry->uniqint);
- }
- }
- /* output free identifiers, in reverse order */
- freeptr = table->freeintlist;
- outputfreeintlist(fileptr, freeptr);
- /* terminate table store with `end' */
- fprintf(fileptr, "end\n");
- }
- } /* ptk_storehashtable */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_storeallhashtables(C(FILE *) fileptr)
- PreANSI(FILE *fileptr)
- /*
- ** \parambegin
- ** \param{FILE *}{fileptr}{pointer to a file}{IN}
- ** \paramend
- ** \blurb{The function writes all the hashtables in the table of hashtables
- ** to the
- ** file \pardesc{fileptr}, which should be opened and writeable.}
- */
- {
- Pint i, count;
-
- count = 0;
- for (i = 0; i < toptable.numtables; i++)
- if (toptable.tablelist[i].tableptr != NULL) {count++;}
-
- /* number of hashtables */
- fprintf(fileptr, "%d\n", count);
-
- /* for each hashtable */
- for (i = 0; i < toptable.numtables; i++)
- {
- if (toptable.tablelist[i].tableptr != NULL)
- {
- fprintf(fileptr, "%s\n", toptable.tablelist[i].strdata);
- ptk_storehashtable(fileptr, toptable.tablelist[i].strdata);
- }
- }
- } /* ptk_storeallhashtables */
-
- /*--------------------------------------------------------------------------*/
-
- static void addstring(C(ptkshashtable *) table, C(Pint) strlength,
- C(char *) str, C(Pint) stid)
- PreANSI(ptkshashtable *table)
- PreANSI(Pint strlength)
- PreANSI(char *str)
- PreANSI(Pint stid)
- /*
- ** \parambegin
- ** \param{ }{table}{hashtable}{IN}
- ** \param{ }{strlength}{length of string to add}{IN}
- ** \param{ }{str}{string to be added in string table}{IN}
- ** \param{ }{stid}{string identifier allocated to string}{IN}
- ** \paramend
- ** \blurb{Inserts the given parameters into a ptksstridentry
- ** structure and sets up the pointers from the hashtable to the string
- ** table and the clash pointers.}
- */
- {
- Pint hashvalue;
- ptkboolean found;
- Pint foundentry;
- Pint dumstid;
-
- hashvalue = hashstring(str, strlength); /* calc hashvalue */
- if (table->hashtable[hashvalue - 1] == NIL)
- {
- /* no collision, so add string */
- if (addstringtotable(table, str, &dumstid))
- {
- table->hashtable[hashvalue - 1] = dumstid - table->minuniqint;
- table->stridtable[dumstid - table->minuniqint].uniqint = stid;
- }
- }
- else
- {
- /* collision, so traverse clash pointers to first free position */
- searchforstring(str, table->hashtable[hashvalue - 1],
- table, &foundentry, &found);
- if (!found)
- {
- /* add into table */
- if (addstringtotable(table, str, &dumstid))
- {
- table->stridtable[foundentry].clashptr = dumstid - table->minuniqint;
- table->stridtable[dumstid - table->minuniqint].prevptr = foundentry;
- table->stridtable[dumstid - table->minuniqint].uniqint = stid;
- }
- }
- } /* else */
- } /* addstring */
-
- /*-------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_restorehashtable(C(FILE *) fileptr, C(char *) tablestr)
- PreANSI(FILE *fileptr)
- PreANSI(char *tablestr)
- /*
- ** \parambegin
- ** \param{FILE *}{fileptr}{pointer to a file}{IN}
- ** \param{char *}{tablestr}{hashtable to insert data from file}{IN}
- ** \paramend
- ** \blurb{This function reads a hashtable from the file \pardesc{fileptr},
- ** and creates it with the name \pardesc{tablestr}. If the hashtable already exists,
- ** it is deleted, and then recreated from the file. The file should be open and
- ** readable when this function is called.}
- */
- {
- #define LINELEN 80
-
- Pint ind;
- Pint minint, maxint;
- Pint numstrs;
- Pint stringlen, uniqint;
- char *strdata;
- char *str;
- Pint id;
- ptkshashtable *table;
-
- /* check if table exists */
- if (ptk_hashtableused(tablestr))
- {
- ptk_delhashtable(tablestr);
- }
- str = (char *)malloc(LINELEN);
- fgets(str, LINELEN, fileptr);
-
- /* get structure identifier range */
- fgets(str, LINELEN, fileptr);
- minint = atoi(str);
- fgets(str, LINELEN, fileptr);
- maxint = atoi(str);
-
- /* create table to be restored */
- ptk_createhashtable(tablestr, minint, maxint);
- table = ptk_stringtotable(tablestr);
-
- /* get number of strings */
- fgets(str, LINELEN, fileptr);
- numstrs = atoi(str);
-
- /* input string table entries */
- for (ind = 0; ind < numstrs; ind++)
- {
- fgets(str, LINELEN, fileptr);
- stringlen = atoi(str);
- strdata = (char *)malloc(stringlen);
- fgets(str, LINELEN, fileptr);
- strncpy(strdata, str, stringlen);
- strdata[stringlen - 1] = '\0';
- fgets(str, LINELEN, fileptr);
- uniqint = atoi(str);
- addstring(table, (stringlen - 1), strdata, uniqint);
- free(strdata);
- }
- /* input free identifiers (stored in reverse order) */
- fgets(str, LINELEN, fileptr);
- id = atoi(str);
- table->freeintlist->freeint = id;
- fgets(str, LINELEN, fileptr);
- while (strncmp(str, "end", 3) != 0)
- {
- id = atoi(str);
- freestrid(&table->freeintlist, id);
- fgets(str, LINELEN, fileptr);
- }
- free(str);
- } /* ptk_restorehashtable */
-
- /*--------------------------------------------------------------------------*/
-
- /*function:external*/
- extern void ptk_restoreallhashtables(C(FILE *) fileptr)
- PreANSI(FILE *fileptr)
- /*
- ** \parambegin
- ** \param{FILE *}{fileptr}{pointer to a file}{IN}
- ** \paramend
- ** \blurb{This function restores all hashtables from a file. Effectively,
- ** \pardesc{ptk\_restorehashtable} (q.v.) is called for each hashtable in
- ** the file. The file should
- ** be open and
- ** readable when this function is called.}
- */
- {
- Pint i, numtables;
- char tablename[255];
-
- fscanf(fileptr, "%d\n", &numtables);
-
- /* for each hashtable in file */
- for (i = 0; i < numtables; i++)
- {
- fscanf(fileptr, "%s\n", tablename);
- ptk_restorehashtable(fileptr, tablename);
- }
- } /* ptk_restoreallhashtables */
-
- /*--------------------------------------------------------------------------*/
-
- /* end of hash.c */
-